/* vim:set noet ts=4: */
/** 
 * scim-python
 * 
 * Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA  02111-1307  USA
 *
 * $Id: $
 */
#include "scim-python.h"
#if Py_UNICODE_SIZE == 2
#  include <glib.h>
#endif

extern PyTypeObject PyIMEngineType;

struct PyIMEngineObject {
	PyListObject list;
	/* Type-specific fields go here. */
	PyIMEngine engine;
};


PyIMEngine::PyIMEngine (
		PyObject			*self,
		PyObject 			*factory,
		PyObject			*config,
		const String		&encoding,
		int				  	id)
  : IMEngineInstanceBase (PyIMEngineFactory::from_pyobject (factory), 
	encoding, id), 
	self (self), 
	factory (factory),
	config (config)
{
	Py_INCREF (self);
	Py_INCREF (factory);
	Py_INCREF (config);
	
	reload_signal_connection = 
		PyConfig_from_pyobject (config)->signal_connect_reload (slot (this, &PyIMEngine::reload_config));
}

PyIMEngine::~PyIMEngine ()
{
	reload_signal_connection.disconnect ();
	
	Py_XDECREF (config);
	Py_XDECREF (factory);
	Py_XDECREF (self);
}

void
PyIMEngine::operator delete (void *p)
{
}

#define PY_CALL(fun) ({								\
	PyObject *pValue = NULL;						\
	PyObject *pFunc = NULL;							\
	pFunc = PyObject_GetAttrString (this->self, fun);\
	if (pFunc != NULL) {							\
		pValue = PyObject_CallObject (pFunc, NULL);	\
		Py_DECREF (pFunc);							\
	}												\
	pValue;})

#define PY_CALL_1(fun, arg1) ({						\
	PyObject *pValue = NULL;						\
	PyObject *pFunc = NULL;							\
	PyObject *pArgs = NULL;							\
	pFunc = PyObject_GetAttrString (this->self, fun);\
	if (pFunc != NULL) {							\
		pArgs = PyTuple_New (1);					\
		PyTuple_SetItem (pArgs, 0, arg1);			\
		pValue = PyObject_CallObject (pFunc, pArgs);\
		Py_DECREF (pFunc);							\
		Py_DECREF (pArgs);							\
	}												\
	pValue;})

#define PY_CHECK_RET(v)							\
	if (v == NULL) {							\
		PyErr_Print ();							\
		return;									\
	}

#define PY_CHECK_RET_VAL(v, val)				\
	if (v == NULL) {							\
		PyErr_Print ();							\
		return val;								\
	}

bool 
PyIMEngine::process_key_event (const KeyEvent &key)
{
	PyObject *pValue;
	
	bool result = false;
	
	pValue = PY_CALL_1("process_key_event", PyKeyEvent_New (key));

	PY_CHECK_RET_VAL (pValue, false);
	
	result = (pValue == Py_True); 
	Py_XDECREF (pValue);
	
	return result;
}

PyObject *
PyIMEngine::py_process_key_event (PyIMEngineObject *self, PyObject *args)
{
	PyErr_SetString (PyExc_NotImplementedError, "process_key_event is not implemented!");
	return NULL;
}


void
PyIMEngine::move_preedit_caret (unsigned int pos)
{
	PyObject *pValue = NULL;
	
	pValue = PY_CALL_1 ("move_preedit_caret", PyInt_FromLong ((unsigned long)pos));
	
	PY_CHECK_RET (pValue);
	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_move_preedit_caret (PyIMEngineObject *self, PyObject *args)
{
	unsigned int pos;

	if (!PyArg_ParseTuple (args, "I:move_preedit_caret", &pos))
		return NULL;

	self->engine.IMEngineInstanceBase::move_preedit_caret (pos);

	Py_INCREF (Py_None);
	return Py_None;
	
}

void
PyIMEngine::select_candidate (unsigned int index)
{
	PyObject *pValue = NULL;
	
	pValue = PY_CALL_1 ("select_candidate", PyInt_FromLong ((unsigned long)index));
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_select_candidate (PyIMEngineObject *self, PyObject *args)
{
	unsigned int index;

	if (!PyArg_ParseTuple (args, "I:select_candidate", &index))
		return NULL;

	self->engine.IMEngineInstanceBase::select_candidate (index);

	Py_INCREF (Py_None);
	return Py_None;
	
}

void
PyIMEngine::update_lookup_table_page_size (unsigned int page_size)
{
	PyObject *pValue = NULL;
	
	pValue = PY_CALL_1 ("update_lookup_table_page_size", PyInt_FromLong ((unsigned long)page_size));
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_update_lookup_table_page_size (PyIMEngineObject *self, PyObject *args)
{
	unsigned int page_size;

	if (!PyArg_ParseTuple (args, "I:update_lookup_table_page_size", &page_size))
		return NULL;

	self->engine.IMEngineInstanceBase::move_preedit_caret (page_size);

	Py_INCREF (Py_None);
	return Py_None;
	
}

void
PyIMEngine::lookup_table_page_up ()
{
	PyObject *pValue = NULL;
	pValue = PY_CALL ("lookup_table_page_up");
	PY_CHECK_RET (pValue);
	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_lookup_table_page_up (PyIMEngineObject *self)
{
	self->engine.IMEngineInstanceBase::lookup_table_page_up ();

	Py_INCREF (Py_None);
	return Py_None;	
}

void
PyIMEngine::lookup_table_page_down ()
{
	PyObject *pValue = NULL;

	pValue = PY_CALL ("lookup_table_page_down");
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_lookup_table_page_down (PyIMEngineObject *self)
{
	self->engine.IMEngineInstanceBase::lookup_table_page_down ();

	Py_INCREF (Py_None);
	return Py_None;	
}

void
PyIMEngine::reset ()
{
	PyObject *pValue = NULL;

	pValue = PY_CALL ("reset");
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_reset (PyIMEngineObject *self)
{
	self->engine.IMEngineInstanceBase::reset ();

	Py_INCREF (Py_None);
	return Py_None;	
}

void
PyIMEngine::focus_in ()
{
	PyObject *pValue = NULL;

	pValue = PY_CALL ("focus_in");
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_focus_in (PyIMEngineObject *self)
{
	self->engine.IMEngineInstanceBase::focus_in ();

	Py_INCREF (Py_None);
	return Py_None;	
}

void
PyIMEngine::focus_out ()
{
	PyObject *pValue = NULL;

	pValue = PY_CALL ("focus_out");
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_focus_out (PyIMEngineObject *self)
{
	self->engine.IMEngineInstanceBase::focus_out ();

	Py_INCREF (Py_None);
	return Py_None;	
}

void
PyIMEngine::trigger_property (const String &property)
{
	PyObject *pValue = NULL;

	pValue = PY_CALL_1 ("trigger_property", PyString_FromString (property.c_str ()));
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_trigger_property (PyIMEngineObject *self, PyObject *args)
{
	char *property;

	if (!PyArg_ParseTuple (args, "s:trigger_property", &property))
		return NULL;

	self->engine.IMEngineInstanceBase::trigger_property (String (property));

	Py_INCREF (Py_None);
	return Py_None;
	
}

void
PyIMEngine::process_helper_event (const String &helper_uuid, const Transaction &trans)
{
	//IMEngineInstanceBase::process_helper_event (helper_uuid, trans);
}

PyObject *
PyIMEngine::py_process_helper_event (PyIMEngineObject *self, PyObject *args)
{
	// TODO: 
	char *helper_uuid;
	PyObject *trans;

	if (!PyArg_ParseTuple (args, "sO:process_helper_event", &helper_uuid, &trans))
		return NULL;

	//self->engine.IMEngineInstanceBase::update_client_capabilities (cap);

	Py_INCREF (Py_None);
	return Py_None;
	
}

void
PyIMEngine::update_client_capabilities (unsigned int cap)
{
	PyObject *pValue = NULL;

	pValue = PY_CALL_1 ("update_client_capabilities", PyInt_FromLong ((unsigned long)cap));
	PY_CHECK_RET (pValue);

	Py_XDECREF (pValue);
}

PyObject *
PyIMEngine::py_update_client_capabilities (PyIMEngineObject *self, PyObject *args)
{
	unsigned int cap;

	if (!PyArg_ParseTuple (args, "I:update_client_capabilities", &cap))
		return NULL;
	self->engine.IMEngineInstanceBase::update_client_capabilities (cap);

	Py_INCREF (Py_None);
	return Py_None;
	
}


void 
PyIMEngine::reload_config (const ConfigPointer &config)
{
	PyObject *pFunc = NULL;
	PyObject *pValue = NULL;
	PyObject *pArgs = NULL;

	pFunc = PyObject_GetAttrString (this->self, "reload_config");
	if (pFunc == NULL)
		goto _failed_out;

	pArgs = Py_BuildValue ("(O)", this->config);
	if (pArgs == NULL)
		goto _failed_out;

	pValue = PyObject_CallObject (pFunc, pArgs);
	if (pValue == NULL)
		goto _failed_out;
	
	goto _success_out;

_failed_out:
	PyErr_Print ();
_success_out:
	Py_XDECREF (pArgs);
	Py_XDECREF (pFunc);
	Py_XDECREF (pValue);
}

IMEngineInstanceBase *
PyIMEngine::from_pyobject (PyObject *object)
{
	PyIMEngineObject *self = (PyIMEngineObject *)object;
	return (IMEngineInstanceBase *) &self->engine;
}

PyObject *
PyIMEngine::py_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	PyIMEngine *self;
	self = (PyIMEngine *)type->tp_alloc (type, 0);
	return (PyObject *)self;
}


int
PyIMEngine::py_init (PyIMEngineObject *self, PyObject *args, PyObject *kwds)
{
	PyObject *factory;
	PyObject *config;
	char *encoding;
	int id;
	
	if (!PyArg_ParseTuple (args, "OOsi:__init__", &factory, &config, &encoding, &id)) {
		PyErr_Print ();
		return -1;
	}

	new (&self->engine) PyIMEngine ((PyObject *)self, 
								factory,
								config,
								String (encoding), id);
	return 0;
}

void
PyIMEngine::py_dealloc (PyIMEngineObject *self)
{
	((PyObject *)self)->ob_type->tp_free (self);
}

PyObject *
PyIMEngine::py_show_preedit_string (PyIMEngineObject *self)
{
	self->engine.show_preedit_string ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_show_aux_string (PyIMEngineObject *self)
{
	self->engine.show_aux_string ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_show_lookup_table (PyIMEngineObject *self)
{
	self->engine.show_lookup_table ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_preedit_string (PyIMEngineObject *self)
{
	self->engine.hide_preedit_string ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_aux_string (PyIMEngineObject *self)
{
	self->engine.hide_aux_string ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_hide_lookup_table (PyIMEngineObject *self)
{
	self->engine.hide_lookup_table ();

	Py_INCREF (Py_None);
	return Py_None;	
}

PyObject *
PyIMEngine::py_update_preedit_caret (PyIMEngineObject *self, PyObject *args)
{
	int caret;
	if (!PyArg_ParseTuple (args, "i:update_preedit_caret", &caret))
			return NULL;
	self->engine.update_preedit_caret (caret);

	Py_INCREF (Py_None);
	return Py_None;	
}
/*
void update_preedit_string (const WideString	&str,
							const AttributeList &attrs = AttributeList ());
*/
PyObject *
PyIMEngine::py_update_preedit_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	PyObject *pAttrs = NULL;
	AttributeList attrs;

#if Py_UNICODE_SIZE == 4
	
	
	if (!PyArg_ParseTuple (args, "u|O:update_preedit_string", &str, &pAttrs))
		return NULL;

	self->engine.update_preedit_string (WideString ((wchar_t *)str), 
								Attributes_FromTupleOrList (pAttrs));
#else
	gunichar *unistr = NULL;
	int size = 0;
	
	if (!PyArg_ParseTuple (args, "u#|O:update_preedit_string", &str, &size, &pAttrs))
		return NULL;

	unistr = g_utf16_to_ucs4 (str, size, NULL, NULL, NULL);

	self->engine.update_preedit_string (WideString ((wchar_t *)unistr), 
								Attributes_FromTupleOrList (pAttrs));
	g_free (unistr);

#endif
	
	Py_INCREF (Py_None);
	return Py_None;
	
}

/*
 * void update_aux_string (const WideString	&str,
 * 						   const AttributeList &attrs = AttributeList ());
 */
PyObject *
PyIMEngine::py_update_aux_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	PyObject *pAttrs = NULL;
	AttributeList attrs;

#if Py_UNICODE_SIZE == 4	
	if (!PyArg_ParseTuple (args, "u|O:update_aux_string", &str, &pAttrs))
		return NULL;
	
	self->engine.update_aux_string (WideString ((wchar_t *)str),
								Attributes_FromTupleOrList (pAttrs));
#else
	int size = 0;
	gunichar *unistr = NULL;
	if (!PyArg_ParseTuple (args, "u#|O:update_aux_string", &str, &size, &pAttrs))
		return NULL;
	
	unistr = g_utf16_to_ucs4 (str, size, NULL, NULL, NULL);
	self->engine.update_aux_string (WideString ((wchar_t *)unistr),
								Attributes_FromTupleOrList (pAttrs));
	g_free (unistr);
#endif
	
	Py_INCREF (Py_None);
	return Py_None;
}

/*
 * void update_lookup_table (const LookupTable &table);
 */
PyObject *
PyIMEngine::py_update_lookup_table (PyIMEngineObject *self, PyObject *args)
{

	PyObject *lookup_table = NULL;
	
	if (!PyArg_ParseTuple (args, "O:update_lookup_table", &lookup_table))
		return NULL;
		
	self->engine.update_lookup_table (PyLookupTable::from_pyobject (lookup_table));
	
	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void commit_string (const WideString &str);
 */
PyObject *
PyIMEngine::py_commit_string (PyIMEngineObject *self, PyObject *args)
{
	Py_UNICODE *str = NULL;
	
#if Py_UNICODE_SIZE == 4	
	if (!PyArg_ParseTuple (args, "u:commit_string", &str))
		return NULL;
	
	self->engine.commit_string (WideString ((wchar_t *)str));
#else
	int size = 0;
	gunichar *unistr = NULL;

	if (!PyArg_ParseTuple (args, "u#:commit_string", &str, &size))
		return NULL;
	
	unistr = g_utf16_to_ucs4 (str, size, NULL, NULL, NULL);
	self->engine.commit_string (WideString ((wchar_t *)unistr));
	g_free (unistr);
#endif
	
	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void forward_key_event (const KeyEvent &key);
 */
PyObject *
PyIMEngine::py_forward_key_event (PyIMEngineObject *self, PyObject *args)
{
	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void register_properties (const PropertyList &properties);
 */
PyObject *
PyIMEngine::py_register_properties (PyIMEngineObject *self, PyObject *args)
{
	PyObject *props = NULL;
	PropertyList proplist;
	int i;

	if (!PyArg_ParseTuple (args, "O:register_properties", &props))
		return NULL;

	if (PyList_Check (props)) {
		for (i = 0; i < PyList_Size (props); i++) {
			PyObject *prop = PyList_GetItem (props, i);
			proplist.push_back (PyProperty_AsProperty (prop));
		}
	}
	else if (PyTuple_Check (props)) {
		for (i = 0; i < PyTuple_Size (props); i++) {
			PyObject *prop = PyTuple_GetItem (props, i);
			proplist.push_back (PyProperty_AsProperty (prop));
		}

	}
	else {
		PyErr_SetString (PyExc_TypeError, "the argument must be a list or a tuple that contains propertys");
		return NULL;
	}
	
	self->engine.register_properties (proplist);

	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void update_property (const Property &property);
 */
PyObject *
PyIMEngine::py_update_property (PyIMEngineObject *self, PyObject *args)
{
	PyObject *prop = NULL;

	if (!PyArg_ParseTuple (args, "O:update_property", &prop))
		return NULL;

	
	self->engine.update_property (PyProperty_AsProperty (prop));

	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void beep ();
 */
PyObject *
PyIMEngine::py_beep (PyIMEngineObject *self)
{
	self->engine.beep ();

	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void start_helper (const String &helper_uuid);
 */
PyObject *
PyIMEngine::py_start_helper (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple (args, "s:start_helper", &str))
		return NULL;
	
	self->engine.start_helper (String (str));

	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void stop_helper (const String &helper_uuid);
 */
PyObject *
PyIMEngine::py_stop_helper (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple (args, "s:stop_helper", &str))
		return NULL;
	
	self->engine.stop_helper (String (str));

	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * void send_helper_event (const String &helper_uuid, const Transaction &trans);
 */
PyObject *
PyIMEngine::py_send_helper_event (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple (args, "s:send_helper_event", &str))
		return NULL;
	
	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * bool get_surrounding_text (WideString &text, 
 * 							int &cursor, i
 * 							nt maxlen_before = -1, 
 * 							int maxlen_after = -1);
 */
PyObject *
PyIMEngine::py_get_surrounding_text (PyIMEngineObject *self, PyObject *args)
{
	char *str = NULL;

	if (!PyArg_ParseTuple (args, "s:get_surrounding_text", &str))
		return NULL;
	
	Py_INCREF (Py_None);
	return Py_None;	
}

/*
 * bool delete_surrounding_text (int offset, int len);
 */
PyObject *
PyIMEngine::py_delete_surrounding_text (PyIMEngineObject *self, PyObject *args)
{
	int offset;
	int len;

	if (!PyArg_ParseTuple (args, "ii:delete_surrounding_text", &offset, &len))
		return NULL;
	
	self->engine.delete_surrounding_text (offset, len);
	
	Py_INCREF (Py_None);
	return Py_None;	
}

PyMethodDef
PyIMEngine::py_methods[] = { 
		{	"show_preedit_string", (PyCFunction)PyIMEngine::py_show_preedit_string, METH_NOARGS,
			"Let scim show the preedit string." 
		}, 
		{	"show_aux_string", (PyCFunction)PyIMEngine::py_show_aux_string, METH_NOARGS,
			"Let scim show the aux string." 
		}, 
		{	"show_lookup_table", (PyCFunction)PyIMEngine::py_show_lookup_table, METH_NOARGS,
			"Let scim show the lookup table that contains candidates." 
		},
		{	"hide_preedit_string", (PyCFunction)PyIMEngine::py_hide_preedit_string, METH_NOARGS,
			"Let scim hide the preedit string." 
		}, 
		{	"hide_aux_string", (PyCFunction)PyIMEngine::py_hide_aux_string, METH_NOARGS,
			"Let scim hide the aux string." 
		}, 
		{	"hide_lookup_table", (PyCFunction)PyIMEngine::py_hide_lookup_table, METH_NOARGS,
			"Let scim hide the lookup table that contains candidates." 
		},		
		{	"update_preedit_caret", (PyCFunction)PyIMEngine::py_update_preedit_caret, METH_VARARGS,
			"Set the caret position of preedit string."
		},
		{	"update_preedit_string", (PyCFunction)PyIMEngine::py_update_preedit_string, METH_VARARGS,
			"Set the preedit string." 
		},
		{	"update_aux_string", (PyCFunction)PyIMEngine::py_update_aux_string, METH_VARARGS,
			"Set the aux string." 
		}, 
		{	"update_lookup_table", (PyCFunction)PyIMEngine::py_update_lookup_table, METH_VARARGS,
			"Set the lookup table that contains candidates." 
		},
		{	"commit_string", (PyCFunction)PyIMEngine::py_commit_string, METH_VARARGS,
			"Commit string to im client."
		}, 
		{	"forward_key_event", (PyCFunction)PyIMEngine::py_forward_key_event, METH_VARARGS,
			"Forward key event to im client." 
		}, 
		{	"register_properties", (PyCFunction)PyIMEngine::py_register_properties, METH_VARARGS,
			"Register properties for this IME." 
		}, 
		{	"update_property", (PyCFunction)PyIMEngine::py_update_property, METH_VARARGS,
			"Update status of IME's property." 
		},
		{	"beep", (PyCFunction)PyIMEngine::py_beep, METH_NOARGS,
			"beep" 
		}, 
		{	"start_helper", (PyCFunction)PyIMEngine::py_start_helper, METH_VARARGS,
			"start helper" 
		}, 
		{	"stop_helper", (PyCFunction)PyIMEngine::py_stop_helper, METH_VARARGS,
			"stop helper" 
		}, 
		{	"send_helper_event", (PyCFunction)PyIMEngine::py_send_helper_event, METH_VARARGS,
			"send event to a helper." 
		}, 
		{	"get_surrounding_text", (PyCFunction)PyIMEngine::py_get_surrounding_text, METH_VARARGS,
			"get surrounding text" 
		}, 
		{	"delete_surrounding_text", (PyCFunction)PyIMEngine::py_delete_surrounding_text, METH_VARARGS,
			"delete surrounding text" 
		},		
		{	"process_key_event", (PyCFunction)PyIMEngine::py_process_key_event, METH_VARARGS,
			"Process key event. Engine develop must implement this funtion to process user input." 
		},		
		{	"move_preedit_caret", (PyCFunction)PyIMEngine::py_move_preedit_caret, METH_VARARGS,
			"move preedit caret" 
		},		
		{	"select_candidate", (PyCFunction)PyIMEngine::py_select_candidate, METH_VARARGS,
			"select candidate" 
		},
		{	"update_lookup_table_page_size", (PyCFunction)PyIMEngine::py_update_lookup_table_page_size, METH_VARARGS,
			"update lookup table page size" 
		},
		{	"lookup_table_page_up", (PyCFunction)PyIMEngine::py_lookup_table_page_up, METH_NOARGS,
			"lookup table page up" 
		},
		{	"lookup_table_page_down", (PyCFunction)PyIMEngine::py_lookup_table_page_down, METH_NOARGS,
			"lookup table page down" 
		},
		{	"reset", (PyCFunction)PyIMEngine::py_reset, METH_NOARGS,
			"Reset this IME." 
		},
		{	"focus_in", (PyCFunction)PyIMEngine::py_focus_in, METH_NOARGS,
			"focus in" 
		},
		{	"focus_out", (PyCFunction)PyIMEngine::py_focus_out, METH_NOARGS,
			"focus_out" 
		},	
		{	"trigger_property", (PyCFunction)PyIMEngine::py_trigger_property, METH_VARARGS,
			"trigger property" 
		},
		{	"process_helper_event", (PyCFunction)PyIMEngine::py_process_helper_event, METH_VARARGS,
			"process_helper_event" 
		},
		{	"update_client_capabilities", (PyCFunction)PyIMEngine::py_update_client_capabilities, METH_VARARGS,
			"update client capabilities" 
		},
		{ NULL }
};

PyTypeObject PyIMEngineType = {
	PyObject_HEAD_INIT (NULL)
	0,						 		/*ob_size*/
	"scim.IMEngine", 				/*tp_name*/
	sizeof (PyIMEngineObject), 		/*tp_basicsize*/
	0,						 		/*tp_itemsize*/
	(destructor)PyIMEngine::py_dealloc,	/*tp_dealloc*/
	0,			  					/*tp_print*/
	0,						 		/*tp_getattr*/
	0,								/*tp_setattr*/
	0,								/*tp_compare*/
	0,			  					/*tp_repr*/
	0,								/*tp_as_number*/
	0,			  					/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	0,			  					/*tp_hash */
	0,								/*tp_call*/
	0,		  						/*tp_str*/
	0,					   			/*tp_getattro*/
	0,								/*tp_setattro*/
	0,					 			/*tp_as_buffer*/
	Py_TPFLAGS_DEFAULT | 
	Py_TPFLAGS_BASETYPE,			/*tp_flags*/
	"IMEngineInstanceBase objects",	/* tp_doc */
	0,					  	/* tp_traverse */
	0,					  	/* tp_clear */
	0,					  	/* tp_richcompare */
	0,					  	/* tp_weaklistoffset */
	0,					  	/* tp_iter */
	0,					  	/* tp_iternext */
	PyIMEngine::py_methods,	/* tp_methods */
	0,			 			/* tp_members */
	0,						/* tp_getset */
	0,						/* tp_base */
	0,						/* tp_dict */
	0,						/* tp_descr_get */
	0,						/* tp_descr_set */
	0,						/* tp_dictoffset */
	(initproc)PyIMEngine::py_init,	/* tp_init */
	0,						 		/* tp_alloc */
	PyIMEngine::py_new,				/* tp_new */	
	PyObject_Del,					/* tp_free */	
};


void init_engine (PyObject *module)
{
	if (PyType_Ready (&PyIMEngineType) < 0)
		return;
	
	Py_INCREF (&PyIMEngineType);
	PyModule_AddObject (module, "IMEngine", (PyObject *)&PyIMEngineType);	
}

